home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 10
/
AACD 10.iso
/
AACD
/
Games
/
MAME
/
src
/
vidhrdw
/
turbo.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-01-25
|
19KB
|
687 lines
/*************************************************************************
Turbo - Sega - 1981
Video Hardware
*************************************************************************/
#ifndef DRAW_CORE_INCLUDE
#include "driver.h"
#include "vidhrdw/generic.h"
/* constants */
#define VIEW_WIDTH (32*8)
#define VIEW_HEIGHT (28*8)
/* external definitions */
UINT8 *turbo_sprite_position;
UINT8 turbo_collision;
/* from machine */
extern UINT8 turbo_opa, turbo_opb, turbo_opc;
extern UINT8 turbo_ipa, turbo_ipb, turbo_ipc;
extern UINT8 turbo_fbpla, turbo_fbcol;
extern UINT8 turbo_segment_data[32];
extern UINT8 turbo_speed;
/* internal data */
static UINT8 *sprite_gfxdata, *sprite_priority;
static UINT8 *road_gfxdata, *road_palette, *road_enable_collide;
static UINT8 *back_gfxdata, *back_palette;
static UINT8 *overall_priority, *collision_map;
/* sprite tracking */
struct sprite_params_data
{
UINT32 *base;
int offset, rowbytes;
int yscale, miny, maxy;
int xscale, xoffs;
};
static struct sprite_params_data sprite_params[16];
static UINT32 *sprite_expanded_data;
/* orientation */
static const struct rectangle game_clip = { 0, VIEW_WIDTH - 1, 64, 64 + VIEW_HEIGHT - 1 };
static struct rectangle adjusted_clip;
static int startx, starty, deltax, deltay;
/* misc other stuff */
static UINT16 *back_expanded_data;
static UINT16 *road_expanded_palette;
static UINT8 drew_frame;
/* prototypes */
static void draw_everything_core_8(struct osd_bitmap *bitmap);
static void draw_everything_core_16(struct osd_bitmap *bitmap);
static void draw_minimal(struct osd_bitmap *bitmap);
/***************************************************************************
Convert the color PROMs into a more useable format.
***************************************************************************/
void turbo_vh_convert_color_prom(unsigned char *palette, unsigned short *colortable, const unsigned char *color_prom)
{
int i;
for (i = 0; i < 512; i++, color_prom++)
{
int bit0, bit1, bit2;
/* bits 4,5,6 of the index are inverted before being used as addresses */
/* to save ourselves lots of trouble, we will undo the inversion when */
/* generating the palette */
int adjusted_index = i ^ 0x70;
/* red component */
bit0 = (*color_prom >> 0) & 1;
bit1 = (*color_prom >> 1) & 1;
bit2 = (*color_prom >> 2) & 1;
palette[adjusted_index * 3 + 0] = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
/* green component */
bit0 = (*color_prom >> 3) & 1;
bit1 = (*color_prom >> 4) & 1;
bit2 = (*color_prom >> 5) & 1;
palette[adjusted_index * 3 + 1] = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
/* blue component */
bit0 = 0;
bit1 = (*color_prom >> 6) & 1;
bit2 = (*color_prom >> 7) & 1;
palette[adjusted_index * 3 + 2] = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
}
/* LED segments colors: black and red */
palette[512 * 3 + 0] = 0x00;
palette[512 * 3 + 1] = 0x00;
palette[512 * 3 + 2] = 0x00;
palette[513 * 3 + 0] = 0xff;
palette[513 * 3 + 1] = 0x00;
palette[513 * 3 + 2] = 0x00;
/* Tachometer colors: Led colors + yellow and green */
palette[514 * 3 + 0] = 0x00;
palette[514 * 3 + 1] = 0x00;
palette[514 * 3 + 2] = 0x00;
palette[515 * 3 + 0] = 0xff;
palette[515 * 3 + 1] = 0xff;
palette[515 * 3 + 2] = 0x00;
palette[516 * 3 + 0] = 0x00;
palette[516 * 3 + 1] = 0x00;
palette[516 * 3 + 2] = 0x00;
palette[517 * 3 + 0] = 0x00;
palette[517 * 3 + 1] = 0xff;
palette[517 * 3 + 2] = 0x00;
}
/***************************************************************************
Video startup/shutdown
***************************************************************************/
int turbo_vh_start(void)
{
int i, j, sprite_length, sprite_bank_size, back_length;
UINT32 sprite_expand[16];
UINT32 *dst;
UINT16 *bdst;
UINT8 *src;
/* allocate the expanded sprite data */
sprite_length = memory_region_length(REGION_GFX1);
sprite_bank_size = sprite_length / 8;
sprite_expanded_data = malloc(sprite_length * 2 * sizeof(UINT32));
if (!sprite_expanded_data)
return 1;
/* allocate the expanded background data */
back_length = memory_region_length(REGION_GFX3);
back_expanded_data = malloc(back_length);
if (!back_expanded_data)
{
free(sprite_expanded_data);
return 1;
}
/* allocate the expanded road palette */
road_expanded_palette = malloc(0x40 * sizeof(UINT16));
if (!road_expanded_palette)
{
free(back_expanded_data);
free(sprite_expanded_data);
return 1;
}
/* determine ROM/PROM addresses */
sprite_gfxdata = memory_region(REGION_GFX1);
sprite_priority = memory_region(REGION_PROMS) + 0x0200;
road_gfxdata = memory_region(REGION_GFX2);
road_palette = memory_region(REGION_PROMS) + 0x0b00;
road_enable_collide = memory_region(REGION_PROMS) + 0x0b40;
back_gfxdata = memory_region(REGION_GFX3);
back_palette = memory_region(REGION_PROMS) + 0x0a00;
overall_priority = memory_region(REGION_PROMS) + 0x0600;
collision_map = memory_region(REGION_PROMS) + 0x0b60;
/* compute the sprite expansion array */
for (i = 0; i < 16; i++)
{
UINT32 value = 0;
if (i & 1) value |= 0x00000001;
if (i & 2) value |= 0x00000100;
if (i & 4) value |= 0x00010000;
if (i & 8) value |= 0x01000000;
/* special value for the end-of-row */
if ((i & 0x0c) == 0x04) value = 0x12345678;
sprite_expand[i] = value;
}
/* expand the sprite ROMs */
src = sprite_gfxdata;
dst = sprite_expanded_data;
for (i = 0; i < 8; i++)
{
/* expand this bank */
for (j = 0; j < sprite_bank_size; j++)
{
*dst++ = sprite_expand[*src >> 4];
*dst++ = sprite_expand[*src++ & 15];
}
/* shift for the next bank */
for (j = 0; j < 16; j++)
if (sprite_expand[j] != 0x12345678) sprite_expand[j] <<= 1;
}
/* expand the background ROMs */
src = back_gfxdata;
bdst = back_expanded_data;
for (i = 0; i < back_length / 2; i++, src++)
{
int bits1 = src[0];
int bits2 = src[back_length / 2];
int newbits = 0;
for (j = 0; j < 8; j++)
{
newbits |= ((bits1 >> (j ^ 7)) & 1) << (j * 2);
newbits |= ((bits2 >> (j ^ 7)) & 1) << (j * 2 + 1);
}
*bdst++ = newbits;
}
/* expand the road palette */
src = road_palette;
bdst = road_expanded_palette;
for (i = 0; i < 0x20; i++, src++)
*bdst++ = src[0] | (src[0x20] << 8);
/* set the default drawing parameters */
startx = game_clip.min_x;
starty = game_clip.min_y;
deltax = deltay = 1;
adjusted_clip = game_clip;
/* adjust our parameters for the specified orientation */
if (Machine->orientation)
{
int temp;
if (Machine->orientation & ORIENTATION_SWAP_XY)
{
temp = startx; startx = starty; starty = temp;
temp = adjusted_clip.min_x; adjusted_clip.min_x = adjusted_clip.min_y; adjusted_clip.min_y = temp;
temp = adjusted_clip.max_x; adjusted_clip.max_x = adjusted_clip.max_y; adjusted_clip.max_y = temp;
}
if (Machine->orientation & ORIENTATION_FLIP_X)
{
startx = adjusted_clip.max_x;
if (!(Machine->orientation & ORIENTATION_SWAP_XY)) deltax = -deltax;
else deltay = -deltay;
}
if (Machine->orientation & ORIENTATION_FLIP_Y)
{
starty = adjusted_clip.max_y;
if (!(Machine->orientation & ORIENTATION_SWAP_XY)) deltay = -deltay;
else deltax = -deltax;
}
}
/* other stuff */
drew_frame = 0;
/* return success */
return 0;
}
void turbo_vh_stop(void)
{
free(sprite_expanded_data);
free(back_expanded_data);
free(road_expanded_palette);
}
/***************************************************************************
Sprite information
***************************************************************************/
static void update_sprite_info(void)
{
struct sprite_params_data *data = sprite_params;
int i;
/* first loop over all sprites and update those whose scanlines intersect ours */
for (i = 0; i < 16; i++, data++)
{
UINT8 *sprite_base = spriteram + 16 * i;
/* snarf all the data */
data->base = sprite_expanded_data + (i & 7) * 0x8000;
data->offset = (sprite_base[6] + 256 * sprite_base[7]) & 0x7fff;
data->rowbytes = (INT16)(sprite_base[4] + 256 * sprite_base[5]);
data->miny = sprite_base[0];
data->maxy = sprite_base[1];
data->xscale = ((5 * 256 - 4 * sprite_base[2]) << 16) / (5 * 256);
data->yscale = (4 << 16) / (sprite_base[3] + 4);
data->xoffs = -1;
}
/* now find the X positions */
for (i = 0; i < 0x200; i++)
{
int value = turbo_sprite_position[i];
if (value)
{
int base = (i & 0x100) >> 5;
int which;
for (which = 0; which < 8; which++)
if (value & (1 << which))
sprite_params[base + which].xoffs = i & 0xff;
}
}
}
/***************************************************************************
Internal draw routines
***************************************************************************/
static void draw_one_sprite(const struct sprite_params_data *data, UINT32 *dest, int xclip, int scanline)
{
int xstep = data->xscale;
int xoffs = data->xoffs;
int xcurr, offset;
UINT32 *src;
/* xoffs of -1 means don't draw */
if (xoffs == -1) return;
/* clip to the road */
xcurr = 0;
if (xoffs < xclip)
{
/* the pixel clock starts on xoffs regardless of clipping; take this into account */
xcurr = ((xclip - xoffs) * xstep) & 0xffff;
xoffs = xclip;
}
/* compute the current data offset */
scanline = ((scanline - data->miny) * data->yscale) >> 16;
offset = data->offset + (scanline + 1) * data->rowbytes;
/* determine the bitmap location */
src = &data->base[offset & 0x7fff];
/* loop over columns */
while (xoffs < VIEW_WIDTH)
{
UINT32 srcval = src[xcurr >> 16];
/* stop on the end-of-row signal */
if (srcval == 0x12345678) break;
dest[xoffs++] |= srcval;
xcurr += xstep;
}
}
static void draw_road_sprites(UINT32 *dest, int scanline)
{
static const struct sprite_params_data *param_list[6] =
{
&sprite_params[0], &sprite_params[8],
&sprite_params[1], &sprite_params[9],
&sprite_params[2], &sprite_params[10]
};
int i;
/* loop over the road sprites */
for (i = 0; i < 6; i++)
{
const struct sprite_params_data *data = param_list[i];
/* if the sprite intersects this scanline, draw it */
if (scanline >= data->miny && scanline < data->maxy)
draw_one_sprite(data, dest, 0, scanline);
}
}
static void draw_offroad_sprites(UINT32 *dest, int road_column, int scanline)
{
static const struct sprite_params_data *param_list[10] =
{
&sprite_params[3], &sprite_params[11],
&sprite_params[4], &sprite_params[12],
&sprite_params[5], &sprite_params[13],
&sprite_params[6], &sprite_params[14],
&sprite_params[7], &sprite_params[15]
};
int i;
/* loop over the offroad sprites */
for (i = 0; i < 10; i++)
{
const struct sprite_params_data *data = param_list[i];
/* if the sprite intersects this scanline, draw it */
if (scanline >= data->miny && scanline < data->maxy)
draw_one_sprite(data, dest, road_column, scanline);
}
}
static void draw_scores(struct osd_bitmap *bitmap)
{
struct rectangle clip;
int offs, x, y;
/* current score */
offs = 31;
for (y = 0; y < 5; y++, offs--)
drawgfx(bitmap, Machine->gfx[0],
turbo_segment_data[offs],
0,
0, 0,
14*8, (2 + y) * 8,
&Machine->drv->visible_area, TRANSPARENCY_NONE, 0);
/* high scores */
for (x = 0; x < 5; x++)
{
offs = 6 + x * 5;
for (y = 0; y < 5; y++, offs--)
drawgfx(bitmap, Machine->gfx[0],
turbo_segment_data[offs],
0,
0, 0,
(20 + 2 * x) * 8, (2 + y) * 8,
&Machine->drv->visible_area, TRANSPARENCY_NONE, 0);
}
/* tachometer */
clip = Machine->drv->visible_area;
clip.min_x = 5*8;
clip.max_x = clip.min_x + 1;
for (y = 0; y < 22; y++)
{
static UINT8 led_color[] = { 2, 2, 2, 2, 1, 1, 0, 0, 0, 0, 0 };
int code = ((y / 2) <= turbo_speed) ? 0 : 1;
drawgfx(bitmap, Machine->gfx[1],
code,
led_color[y / 2],
0,0,
5*8, y*2+8,
&clip, TRANSPARENCY_NONE, 0);
if (y % 3 == 2)
clip.max_x++;
}
/* shifter status */
if (readinputport(0) & 0x04)
{
drawgfx(bitmap, Machine->gfx[2], 'H', 0, 0,0, 2*8,3*8, &Machine->drv->visible_area, TRANSPARENCY_NONE, 0);
drawgfx(bitmap, Machine->gfx[2], 'I', 0, 0,0, 2*8,4*8, &Machine->drv->visible_area, TRANSPARENCY_NONE, 0);
}
else
{
drawgfx(bitmap, Machine->gfx[2], 'L', 0, 0,0, 2*8,3*8, &Machine->drv->visible_area, TRANSPARENCY_NONE, 0);
drawgfx(bitmap, Machine->gfx[2], 'O', 0, 0,0, 2*8,4*8, &Machine->drv->visible_area, TRANSPARENCY_NONE, 0);
}
}
/***************************************************************************
Master refresh routine
***************************************************************************/
void turbo_vh_eof(void)
{
/* only do collision checking if we didn't draw */
if (!drew_frame)
{
update_sprite_info();
draw_minimal(Machine->scrbitmap);
}
drew_frame = 0;
}
void turbo_vh_screenrefresh(struct osd_bitmap *bitmap, int full_refresh)
{
/* update the sprite data */
update_sprite_info();
/* perform the actual drawing */
if (bitmap->depth == 8)
draw_everything_core_8(bitmap);
else
draw_everything_core_16(bitmap);
/* draw the LEDs for the scores */
draw_scores(bitmap);
/* indicate that we drew this frame, so that the eof callback doesn't bother doing anything */
drew_frame = 1;
}
/***************************************************************************
Road drawing generators
***************************************************************************/
#define DRAW_CORE_INCLUDE
#define FULL_DRAW 1
#define DRAW_FUNC draw_everything_core_8
#define TYPE UINT8
#include "turbo.c"
#undef TYPE
#undef DRAW_FUNC
#define DRAW_FUNC draw_everything_core_16
#define TYPE UINT16
#include "turbo.c"
#undef TYPE
#undef DRAW_FUNC
#undef FULL_DRAW
#define FULL_DRAW 0
#define DRAW_FUNC draw_minimal
#define TYPE UINT8
#include "turbo.c"
#undef TYPE
#undef DRAW_FUNC
#undef FULL_DRAW
#else
/***************************************************************************
Road drawing routine
***************************************************************************/
static void DRAW_FUNC(struct osd_bitmap *bitmap)
{
TYPE *base = &((TYPE *)bitmap->line[starty])[startx];
UINT32 sprite_buffer[VIEW_WIDTH + 256];
UINT8 *overall_priority_base = &overall_priority[(turbo_fbpla & 8) << 6];
UINT8 *sprite_priority_base = &sprite_priority[(turbo_fbpla & 7) << 7];
UINT8 *road_gfxdata_base = &road_gfxdata[(turbo_opc << 5) & 0x7e0];
UINT16 *road_palette_base = &road_expanded_palette[(turbo_fbcol & 1) << 4];
int dx = deltax, dy = deltay, rowsize = (bitmap->line[1] - bitmap->line[0]) * 8 / bitmap->depth;
UINT16 *colortable;
int x, y, i;
/* expand the appropriate delta */
if (Machine->orientation & ORIENTATION_SWAP_XY)
dx *= rowsize;
else
dy *= rowsize;
/* determine the color offset */
colortable = &Machine->pens[(turbo_fbcol & 6) << 6];
/* loop over rows */
for (y = 4; y < VIEW_HEIGHT - 4; y++, base += dy)
{
int sel, coch, babit, slipar_acciar, area, area1, area2, area3, area4, area5, road = 0;
UINT32 *sprite_data = sprite_buffer;
TYPE *dest = base;
/* compute the Y sum between opa and the current scanline (p. 141) */
int va = (y + turbo_opa) & 0xff;
/* the upper bit of OPC inverts the road */
if (!(turbo_opc & 0x80)) va ^= 0xff;
/* clear the sprite buffer and draw the road sprites */
memset(sprite_buffer, 0, VIEW_WIDTH * sizeof(UINT32));
draw_road_sprites(sprite_buffer, y);
/* loop over 8-pixel chunks */
dest += dx * 8;
sprite_data += 8;
for (x = 8; x < VIEW_WIDTH; x += 8)
{
int area5_buffer = road_gfxdata_base[0x4000 + (x >> 3)];
UINT8 back_data = videoram[(y / 8) * 32 + (x / 8) - 33];
UINT16 backbits_buffer = back_expanded_data[(back_data << 3) | (y & 7)];
/* loop over columns */
for (i = 0; i < 8; i++, dest += dx)
{
UINT32 sprite = *sprite_data++;
/* compute the X sum between opb and the current column; only the carry matters (p. 141) */
int carry = (x + i + turbo_opb) >> 8;
/* the carry selects which inputs to use (p. 141) */
if (carry)
{
sel = turbo_ipb;
coch = turbo_ipc >> 4;
}
else
{
sel = turbo_ipa;
coch = turbo_ipc & 15;
}
/* at this point we also compute area5 (p. 141) */
area5 = (area5_buffer >> 3) & 0x10;
area5_buffer <<= 1;
/* now look up the rest of the road bits (p. 142) */
area1 = road_gfxdata[0x0000 | ((sel & 15) << 8) | va];
area1 = ((area1 + x + i) >> 8) & 0x01;
area2 = road_gfxdata[0x1000 | ((sel & 15) << 8) | va];
area2 = ((area2 + x + i) >> 7) & 0x02;
area3 = road_gfxdata[0x2000 | ((sel >> 4) << 8) | va];
area3 = ((area3 + x + i) >> 6) & 0x04;
area4 = road_gfxdata[0x3000 | ((sel >> 4) << 8) | va];
area4 = ((area4 + x + i) >> 5) & 0x08;
/* compute the final area value and look it up in IC18/PR1115 (p. 144) */
area = area5 | area4 | area3 | area2 | area1;
babit = road_enable_collide[area] & 0x07;
/* note: SLIPAR is 0 on the road surface only */
/* ACCIAR is 0 on the road surface and the striped edges only */
slipar_acciar = road_enable_collide[area] & 0x30;
if (!road && (slipar_acciar & 0x20))
{
road = 1;
draw_offroad_sprites(sprite_buffer, x + i + 2, y);
}
/* perform collision detection here */
turbo_collision |= collision_map[((sprite >> 24) & 7) | (slipar_acciar >> 1)];
/* we only need to continue if we're actually drawing */
if (FULL_DRAW)
{
int bacol, red, grn, blu, priority, backbits, mx;
/* also use the coch value to look up color info in IC13/PR1114 and IC21/PR1117 (p. 144) */
bacol = road_palette_base[coch & 15];
/* at this point, do the character lookup */
backbits = backbits_buffer & 3;
backbits_buffer >>= 2;
backbits = back_palette[backbits | (back_data & 0xfc)];
/* look up the sprite priority in IC11/PR1122 */
priority = sprite_priority_base[sprite >> 25];
/* use that to look up the overall priority in IC12/PR1123 */
mx = overall_priority_base[(priority & 7) | ((sprite >> 21) & 8) | ((back_data >> 3) & 0x10) | ((backbits << 2) & 0x20) | (babit << 6)];
/* the input colors consist of a mix of sprite, road and 1's & 0's */
red = 0x040000 | ((bacol & 0x001f) << 13) | ((backbits & 1) << 12) | ((sprite << 4) & 0x0ff0);
grn = 0x080000 | ((bacol & 0x03e0) << 9) | ((backbits & 2) << 12) | ((sprite >> 3) & 0x1fe0);
blu = 0x100000 | ((bacol & 0x7c00) << 5) | ((backbits & 4) << 12) | ((sprite >> 10) & 0x3fc0);
/* we then go through a muxer; normally these values are inverted, but */
/* we've already taken care of that when we generated the palette */
red = (red >> mx) & 0x10;
grn = (grn >> mx) & 0x20;
blu = (blu >> mx) & 0x40;
*dest = colortable[mx | red | grn | blu];
}
}
}
}
}
#endif